<script setup>
import { BaseEdge, EdgeLabelRenderer, getBezierPath, useEdge, useVueFlow } from '@vue-flow/core';
import { TransitionPresets, useDebounceFn, useTransition, watchDebounced } from '@vueuse/core';
import { computed, defineEmits, ref } from 'vue';

const props = defineProps({
  id: {
    type: String,
    required: true,
  },
  source: {
    type: String,
    required: true,
  },
  target: {
    type: String,
    required: true,
  },
  sourceX: {
    type: Number,
    required: true,
  },
  sourceY: {
    type: Number,
    required: true,
  },
  targetX: {
    type: Number,
    required: true,
  },
  targetY: {
    type: Number,
    required: true,
  },
  sourcePosition: {
    type: String,
    required: true,
  },
  targetPosition: {
    type: String,
    required: true,
  },
  data: {
    type: Object,
    required: false,
  },
  markerEnd: {
    type: String,
    required: false,
  },
  style: {
    type: Object,
    required: false,
  },
})

const emits = defineEmits(['edgeControlsOpen','edgeControlsClose']);

const curve = ref()

const dot = ref()

const transform = ref({ x: 0, y: 0 })

const showDot = ref(false)

const { onNodeDoubleClick, fitBounds, fitView, removeEdges, onEdgeClick } = useVueFlow()
const { edge } = useEdge()

const path = computed(() =>
  getBezierPath({
    sourceX: props.sourceX,
    sourceY: props.sourceY,
    sourcePosition: props.sourcePosition,
    targetX: props.targetX,
    targetY: props.targetY,
    targetPosition: props.targetPosition,
  }),
)

const debouncedFitBounds = useDebounceFn(fitBounds, 1, { maxWait: 1 })

onNodeDoubleClick(({ node }) => {
  console.log('node double click', node)
  const isSource = props.source === node.id
  const isTarget = props.target === node.id

  if (!showDot.value && (isSource || isTarget)) {
    showDot.value = true
    let totalLength = curve.value.getTotalLength()
    const initialPos = ref(isSource ? 0 : totalLength)
    let stopHandle

    const output = useTransition(initialPos, {
      duration: Math.floor(totalLength / 2 / 100) * 1000,
      transition: TransitionPresets.easeOutCubic,
      onFinished: () => {
        stopHandle?.()
        showDot.value = false
        fitView({
          nodes: [isSource ? props.target : props.source],
          duration: 500,
        })
      },
    })

    transform.value = curve.value.getPointAtLength(output.value)

    debouncedFitBounds(
      {
        width: 100,
        height: 200,
        x: transform.value.x - 100,
        y: transform.value.y - 100,
      },
      { duration: 500 },
    )

    setTimeout(() => {
      initialPos.value = isSource ? totalLength : 0

      stopHandle = watchDebounced(
        output,
        (next) => {
          if (!showDot.value) {
            return
          }

          const nextLength = curve.value.getTotalLength()

          if (totalLength !== nextLength) {
            totalLength = nextLength
            initialPos.value = isSource ? totalLength : 0
          }

          transform.value = curve.value.getPointAtLength(next)

          debouncedFitBounds({
            width: 100,
            height: 200,
            x: transform.value.x - 100,
            y: transform.value.y - 100,
          })
        },
        { debounce: 1 },
      )
    }, 500)
  }
})

// 点击连线
onEdgeClick((event, edge) => {
  // edgeActive.value = true
  // currEdge.value = event.edge
})

const edgeControlsOpenClick = () => {
  emits('edgeControlsClose', {})
  edge.selected = true
  emits('edgeControlsOpen', edge)
}
</script>

<script>
export default {
  inheritAttrs: false,
}
</script>

<template>
  <path :id="id" ref="curve" :style="style" class="vue-flow__edge-path" :d="path[0]" :marker-end="markerEnd" />

  <Transition name="fade">
    <circle
      v-if="showDot"
      ref="dot"
      r="5"
      cy="0"
      cx="0"
      :transform="`translate(${transform.x}, ${transform.y})`"
      style="fill: #fdd023"
    />
  </Transition>

  <BaseEdge
    :id="id"
    :style="style"
    :path="path[0]"
    :marker-end="markerEnd"
  />

  <EdgeLabelRenderer>
    <div
      v-if="edge.label"
      @click.stop.prevent="edgeControlsOpenClick"
      :style="{
        background: '#fff',
        pointerEvents: 'all',
        position: 'absolute',
        transform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,
      }"
      class="nodrag nopan edge-line-label"
    >
      <span>{{ edge.label }}</span>
      <button
        v-if="false"
        class="edgebutton"
        @click="removeEdges(id)"
      >
        ×
      </button>
    </div>
  </EdgeLabelRenderer>
</template>

<style>
.fade-enter-active,.fade-leave-active{transition:opacity .3s ease}
.fade-enter-from,.fade-leave-to{opacity:0}

.edgebutton{
  border-radius:10px;
  cursor:pointer
}

.edgebutton:hover{
  box-shadow:0 0 0 2px #10b98180,0 0 0 4px #10b981;
  transform:scale(1.1);
  transition:all ease .5s
}

.edge-line-label{
  padding: 3px;
  border-radius: 2px;
  background-color: #fff;
}
</style>
